// bzoj2594
// 题意：给定 n(≤100000) 个点 m(≤1000000) 条边的无向图（城市，水管），
//       现在定义两点之间的维修费用为所有联通该两点的道路中最长边的最小值，
//       现在要支持两种操作：
//
//       1. 查询两点的维修费用;
//       2. 删除一条保证存在的边.
//
//       操作个数 q(≤100000)。
//
// 题解：要求的费用是最长边最大费用最小，可以考虑维护最小生成森林，
//       然后不断维护两点的最大边权。 动态维护可以考虑用动态树（这里用了link-cut-tree）。
//       现在有两个问题：
//
//       1. 动态树删边维护最小生成森林不太方便;
//       2. 动态树不能直接维护边权。
//
//       对于第一个问题，我们可以离线做。读入所有询问，然后倒过来，
//       先用所有要删的边之外的边构造出lct，然后删边就变成加边了，就可以做了。
//       对于第二个问题，也不难解决，我们把每条边再给一个点，然后分别和这条边两端的点相连，
//       把两端的点权设成零，该边对应的点权就是该边的费用，这样就成功转换了。
//
//       这题我遇到一个比较囧的情况，一开始如果用lct自带的find_root操作
//       来找根判断是不是在同一棵树会超时，而改成并查集就过了。
//       我用 jzp的数据生成器 生成的数据测试了一下， 用find_root慢了一倍……
// run: time -p $exec < tube10.in > output
// opt: 0
// flag: -g
#include <cstdio>
#include <algorithm>

int const maxn = 1200000;
int const maxm = 1000007;
int const maxq = 1000007;

struct edge
{
	int from, to, cost, index;
} edges[maxm];

bool deleted_edge[maxm];

bool operator<(edge const & a, edge const & b)
{
	return a.cost < b.cost;
}

bool cmp(edge const & a, edge const & b)
{
	return a.from < b.from || (a.from == b.from && a.to < b.to);
}


bool cmp2(edge const & a, edge const & b)
{
	return a.index < b.index;
}

struct query
{
	int opt, x, y, index;
} queries[maxq];

int value[maxn];
int ans[maxq];
int father[maxn];
int n, m, q, tot;

int get_father(int x)
{
	return father[x] == x ? x : father[x] = get_father(father[x]);
}

struct node
{
	void push_down();
	void update();
	int id, max;
	bool rev;
	int parent, child[2];
} memory[maxn], *nil = memory;

void node::push_down()
{
	if (this == nil) return;
	if (rev) {
		std::swap(child[0], child[1]);
		memory[child[0]].rev ^= true;
		memory[child[1]].rev ^= true;
		rev = false;
	}
}

void node::update()
{
	push_down(); memory[child[0]].push_down(); memory[child[1]].push_down();
	max = id;
	if (value[memory[child[0]].max] > value[max]) max = memory[child[0]].max;
	if (value[memory[child[1]].max] > value[max]) max = memory[child[1]].max;
}

void rotate(int u, int is_left)
{
	int p = memory[u].parent;
	memory[p].child[!is_left] = memory[u].child[is_left];
	if (memory[u].child[is_left] != 0) memory[memory[u].child[is_left]].parent = p;
	memory[u].parent = memory[p].parent;
	if (memory[memory[p].parent].child[0] == p) memory[memory[u].parent].child[0] = u;
	else if (memory[memory[p].parent].child[1] == p) memory[memory[u].parent].child[1] = u;
	memory[u].child[is_left] = p;
	memory[p].parent = u;
	memory[p].update();

}

void splay(int u)
{
	if (!u) return;
	memory[u].push_down();
	for (int v, w; (v = memory[u].parent) != 0 && (memory[v].child[0] == u || memory[v].child[1] == u); ) {
		if ((w = memory[v].parent) != 0 && (memory[w].child[0] == v || memory[w].child[1] == v)) {
			memory[w].push_down(); memory[v].push_down(); memory[u].push_down();
			bool is_left = v == memory[memory[v].parent].child[0];
			if (u == memory[v].child[is_left])
				rotate(u, !is_left), rotate(u, is_left);
			else
				rotate(v, is_left), rotate(u, is_left);
		} else {
			memory[v].push_down(); memory[u].push_down();
			rotate(u, u == memory[v].child[0]);
			break;
		}
	}
	memory[u].update();
}

int access(int u)
{
	int v = 0;
	for (; u; v = u, u = memory[u].parent) splay(u), memory[u].child[1] = v;
	return v;
}

void make_root(int u)
{
	memory[access(u)].rev ^= true;
	splay(u);
}

int get_root(int u)
{
	for (u = access(u); memory[u].push_down(), memory[u].child[0]; u = memory[u].child[0]);
	return u;
}

void link(int u, int v)
{
	make_root(u);
	memory[u].parent = v;
	access(u);
}

void cut(int u, int v)
{
	make_root(u);
	access(v);
	splay(v);
	memory[memory[v].child[0]].parent = 0;
	memory[v].child[0] = 0;
	memory[v].update();
}

void init(int n)
{
	for (int i = 0; i <= n; i++) {
		memory[i].parent = memory[i].child[0] = memory[i].child[1] = 0;
		memory[i].id = memory[i].max = i;
		memory[i].rev = false;
		father[i] = i;
	}
}

int query_max(int u, int v)
{
	make_root(u);
	access(v);
	splay(v);
	return memory[v].max;
}

const int BZ = 30 << 20;
char Buf[BZ + 1], *buf = Buf;

template <class T>
inline void scan(T &a) // method2: for huge input
{
	bool flag = false;
	for (a = 0; *buf < '0' || *buf > '9'; ++buf)
		if (*buf == '-') flag = true;
	for (; *buf >= '0' && *buf <= '9'; buf++)
		a = a * 10 + (*buf - '0');
	if (flag) a = -a;
}

int find_index(int x, int y)
{
	int l = 1, r = m;
	while (true) {
		int mid = (l + r) / 2;
		if (edges[mid].from == x && edges[mid].to == y) return edges[mid].index;
		if (edges[mid].from < x || (edges[mid].from == x && edges[mid].to < y))
			l = mid + 1;
		else
			r = mid - 1;
	}
}

int main()
{
	std::fread(Buf, 1, BZ, stdin); // method2

	scan(n); scan(m); scan(q);

	for (int i = 1; i <= m; i++) {
		scan(edges[i].from);
		scan(edges[i].to);
		scan(edges[i].cost);
		if (edges[i].from > edges[i].to) std::swap(edges[i].from, edges[i].to);
	}
	std::sort(edges + 1, edges + m + 1);
	for (int i = 1; i <= m; i++) edges[i].index = i;

	std::sort(edges + 1, edges + m + 1, cmp);
	for (int i = 0; i < q; i++) {
		scan(queries[i].opt);
		scan(queries[i].x);
		scan(queries[i].y);
		if (queries[i].x > queries[i].y) std::swap(queries[i].x, queries[i].y);

		if (queries[i].opt == 2) {
			int t = queries[i].index = find_index(queries[i].x, queries[i].y);
			deleted_edge[t] = true;
		}
	}

	std::sort(edges + 1, edges + m + 1, cmp2);
	init(n + m);

	for (int i = 1; i <= n; i++) value[i] = 0;
	for (int i = 1; i <= m; i++) value[n + i] = edges[i].cost;

	// init graph construct lct
	for (int i = 1; i <= m; i++) {
		if (deleted_edge[i]) continue;
		int f1 = get_father(edges[i].from);
		int f2 = get_father(edges[i].to);
		if (f1 == f2) continue;
		link(edges[i].from, n + i);
		link(edges[i].to,   n + i);
		father[f1] = f2;
	}

	for (int i = q - 1; i >= 0; i--) {
		if (queries[i].opt == 1) {
			ans[tot++] = value[query_max(queries[i].x, queries[i].y)];
		} else {
			int t = query_max(queries[i].x, queries[i].y);
			int ti = queries[i].index;
			if (value[t] > edges[ti].cost) {
				cut(t, edges[t - n].from);
				cut(t, edges[t - n].to);
				link(ti + n, edges[ti].from);
				link(ti + n, edges[ti].to);
			}
		}
	}

	for (int i = tot - 1; i >= 0; i--)
		std::printf("%d\n", ans[i]);
}

